package com.hand.wfive.view.sign;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.qmuiteam.qmui.util.QMUIDisplayHelper;
import com.hand.wfive.R;
import com.hand.wfive.view.sign.pen.BasePen;
import com.hand.wfive.view.sign.pen.Eraser;
import com.hand.wfive.view.sign.pen.SteelPen;
import com.hand.wfive.view.sign.util.StepOperator;

public class PaintView extends View {

    public static final int TYPE_PEN = 0;
    public static final int TYPE_ERASER = 1;

    private Paint mPaint;
    private Canvas mCanvas;
    private Bitmap mBitmap;
    private BasePen mStokeBrushPen;

    /**
     * 是否允许写字
     */
    private boolean isFingerEnable = true;
    /**
     * 是否橡皮擦模式
     */
    private boolean isEraser = false;

    /**
     * 是否有绘制
     */
    private boolean hasDraw = false;

    /**
     * 画笔轨迹记录
     */
    private StepOperator mStepOperation;

    private StepCallback mCallback;

    /**
     * 是否可以撤销
     */
    private boolean mCanUndo;
    /**
     * 是否可以恢复
     */
    private boolean mCanRedo;

    private int mWidth;
    private int mHeight;

    // 是否正在绘制
    private boolean isDrawing = false;

    private Eraser eraser;

    private int mPaintColor = Color.BLACK;

    public PaintView(Context context) {
        this(context, null);
    }

    public PaintView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PaintView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        this.mWidth = getMeasuredWidth();
        this.mHeight = getMeasuredHeight();

        init();
    }

    /**
     * 初始化画板
     */
    private void init() {
        mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
        mStokeBrushPen = new SteelPen();

        initPaint();

        mCanvas = new Canvas(mBitmap);
        mCanvas.drawColor(Color.TRANSPARENT);

        mStepOperation = new StepOperator();
        mStepOperation.addBitmap(mBitmap);
        //橡皮擦
        eraser = new Eraser(getResources().getDimensionPixelSize(R.dimen.dp_28));
    }

    /**
     * 初始画笔设置
     */
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setColor(mPaintColor);
        mPaint.setStrokeWidth(QMUIDisplayHelper.dp2px(getContext(), 10));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAlpha(0xFF);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeMiter(1.0f);
        mStokeBrushPen.setPaint(mPaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
        if (!isEraser) {
            mStokeBrushPen.draw(canvas);
        }
        super.onDraw(canvas);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //记录手写笔类型：触控笔/手指
        int toolType = event.getToolType(event.getActionIndex());
        if (!isFingerEnable && toolType != MotionEvent.TOOL_TYPE_STYLUS) {
            return false;
        }
        if (isEraser) {
            eraser.handleEraserEvent(event, mCanvas);
        } else {
            mStokeBrushPen.onTouchEvent(event, mCanvas);
        }

        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_CANCEL:
                isDrawing = false;
                break;
            case MotionEvent.ACTION_MOVE:
                hasDraw = true;
                mCanUndo = true;
                isDrawing = true;
                break;
            case MotionEvent.ACTION_UP:
                if (mStepOperation != null) {
                    if (isDrawing){
                        mStepOperation.addBitmap(mBitmap);
                    }
                    mCanUndo = !mStepOperation.currentIsFirst();
                    mCanRedo = !mStepOperation.currentIsLast();
                }
                if (mCallback != null) {
                    mCallback.onOperateStatusChanged();
                }
                isDrawing = false;
                break;
            default:
                break;
        }
        invalidate();
        return true;
    }

    /**
     * @return 判断是否有绘制内容在画布上
     */
    public boolean isEmpty() {
        return !hasDraw;
    }

    /**
     * 撤销
     */
    public void undo() {
        if (mStepOperation == null || !mCanUndo) {
            return;
        }
        if (!mStepOperation.currentIsFirst()) {
            mCanUndo = true;
            mStepOperation.undo(mBitmap);
            hasDraw = true;
            invalidate();

            if (mStepOperation.currentIsFirst()) {
                mCanUndo = false;
                hasDraw = false;
            }
        } else {
            mCanUndo = false;
            hasDraw = false;
        }
        if (!mStepOperation.currentIsLast()) {
            mCanRedo = true;
        }
        if (mCallback != null) {
            mCallback.onOperateStatusChanged();
        }
    }

    /**
     * 恢复
     */
    public void redo() {
        if (mStepOperation == null || !mCanRedo) {
            return;
        }
        if (!mStepOperation.currentIsLast()) {
            mCanRedo = true;
            mStepOperation.redo(mBitmap);
            hasDraw = true;
            invalidate();
            if (mStepOperation.currentIsLast()) {
                mCanRedo = false;
            }
        } else {
            mCanRedo = false;
        }
        if (!mStepOperation.currentIsFirst()) {
            mCanUndo = true;
        }
        if (mCallback != null) {
            mCallback.onOperateStatusChanged();
        }
    }

    /**
     * 清除画布，记得清除点的集合
     */
    public void reset() {
        mBitmap.eraseColor(Color.TRANSPARENT);
        hasDraw = false;
        mStokeBrushPen.clear();
        if (mStepOperation != null) {
            mStepOperation.reset();
            mStepOperation.addBitmap(mBitmap);
        }
        mCanRedo = false;
        mCanUndo = false;
        if (mCallback != null) {
            mCallback.onOperateStatusChanged();
        }
        invalidate();
    }

    public void release() {
        destroyDrawingCache();
        if (mBitmap != null) {
            mBitmap.recycle();
            mBitmap = null;
        }
        if (mStepOperation != null) {
            mStepOperation.freeBitmaps();
            mStepOperation = null;
        }
    }

    public interface StepCallback {
        /**
         * 操作变更
         */
        void onOperateStatusChanged();
    }

    public void setStepCallback(StepCallback callback) {
        this.mCallback = callback;
    }

    /**
     * 设置画笔样式
     */
    public void setPenType(int penType) {
        isEraser = false;
        switch (penType) {
            case TYPE_PEN:
                mStokeBrushPen = new SteelPen();
                break;
            case TYPE_ERASER:
                isEraser = true;
                break;
        }
        // 设置
        if (mStokeBrushPen.isNullPaint()) {
            mStokeBrushPen.setPaint(mPaint);
        }
        invalidate();
    }

    /**
     * 设置画笔大小
     *
     * @param width 大小
     */
    public void setPaintWidth(int width) {
        if (mPaint != null) {
            mPaint.setStrokeWidth(QMUIDisplayHelper.dp2px(getContext(), width));
            mStokeBrushPen.setPaint(mPaint);
            invalidate();
        }
    }

    /**
     * 设置画笔颜色
     *
     * @param color 颜色
     */
    public void setPaintColor(int color) {
        if (mPaint != null) {
            mPaintColor = color;
            mPaint.setColor(mPaintColor);
            mStokeBrushPen.setPaint(mPaint);
            invalidate();
        }
    }

    public int getPaintColor() {
        return mPaintColor;
    }

    public boolean isFingerEnable() {
        return isFingerEnable;
    }

    public void setFingerEnable(boolean fingerEnable) {
        isFingerEnable = fingerEnable;
    }

    public boolean isEraser() {
        return isEraser;
    }

    public boolean canUndo() {
        return mCanUndo;
    }

    public boolean canRedo() {
        return mCanRedo;
    }

    public Bitmap getBitmap() {
        return mBitmap;
    }

}
